package pers.xhh.frontapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.xhh.frontapi.common.Constant;
import pers.xhh.frontapi.common.Mi;
import pers.xhh.frontapi.common.ResultCode;
import pers.xhh.frontapi.dao.MiOrderDao;
import pers.xhh.frontapi.entity.*;
import pers.xhh.frontapi.entity.to.order.OrderCreateTo;
import pers.xhh.frontapi.entity.to.order.OrderSubmitTo;
import pers.xhh.frontapi.entity.vo.cart.CartItem;
import pers.xhh.frontapi.entity.vo.order.OrderConfirmVo;
import pers.xhh.frontapi.entity.vo.order.OrderItemVo;
import pers.xhh.frontapi.enume.OrderStatusEnum;
import pers.xhh.frontapi.exception.MiException;
import pers.xhh.frontapi.interceptor.AuthenticationInterceptor;
import pers.xhh.frontapi.service.MiOrderItemService;
import pers.xhh.frontapi.service.MiOrderService;
import pers.xhh.frontapi.service.MiReceiverService;
import pers.xhh.frontapi.service.MiWareService;
import pers.xhh.frontapi.util.DateUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author wei-xhh
 * @date 2020-11-22
 */
@Service
public class MiOrderServiceImpl extends ServiceImpl<MiOrderDao, MiOrderEntity> implements MiOrderService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    MiReceiverService miReceiverService;

    @Autowired
    MiOrderItemService miOrderItemService;

    @Autowired
    MiWareService miWareService;


    @Override
    public Mi orderInfo() {

        // 获取登录后的信息
        MiUserEntity miUserEntity =
                AuthenticationInterceptor.threadLocal.get();

        String cartKey = Constant.CART_PREFIX + miUserEntity.getUserId();
        BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = cartOps.values();
        // ->订单数据
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        if (values != null && values.size() > 0) {
            List<OrderItemVo> orderItemVoList = new ArrayList<>();
            for (Object value : values) {
                String str = (String) value;
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    CartItem cartItem = objectMapper.readValue(str, CartItem.class);
                    if (cartItem.getCheck()) {
                        OrderItemVo orderItemVo = new OrderItemVo();
                        orderItemVo.setGoodsId(cartItem.getGoodsId());
                        orderItemVo.setTitle(cartItem.getTitle());
                        orderItemVo.setImage(cartItem.getImage());
                        orderItemVo.setAttrs(cartItem.getAttr());
                        orderItemVo.setPrice(cartItem.getPrice());
                        orderItemVo.setCount(cartItem.getCount());
                        orderItemVo.setTotalPrice(cartItem.getTotalPrice());
                        orderItemVoList.add(orderItemVo);
                    }
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }

            orderConfirmVo.setItems(orderItemVoList);

            // ->查询该用户下的所有地址
            Integer userId = miUserEntity.getUserId();
            List<MiReceiverEntity> receiverEntities =
                    miReceiverService.list(new QueryWrapper<MiReceiverEntity>().eq("user_id", userId));
            orderConfirmVo.setAddress(receiverEntities);

            // ->防重验证
            String token = UUID.randomUUID().toString().replace("-", "");
            redisTemplate.opsForValue().set(Constant.USER_ORDER_TOKEN_PREFIX + miUserEntity.getUserId(), token, 30, TimeUnit.MINUTES);
            orderConfirmVo.setOrderToken(token);

        }

        return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), orderConfirmVo);
    }

    @Transactional
    @Override
    public Mi confirmOrder(OrderSubmitTo orderSubmitTo) {
        String orderToken = orderSubmitTo.getOrderToken();
        Integer addrId = Integer.parseInt(orderSubmitTo.getAddrId());
        BigDecimal payPrice = orderSubmitTo.getPayPrice();
        Integer payType = Integer.parseInt(orderSubmitTo.getPayType());
        String note = orderSubmitTo.getNote();
        if(payPrice == null){
            return Mi.error(ResultCode.ERROR1201.getMessage(), ResultCode.ERROR1201.getStatus());
        }

        if (orderToken == null) {
            return Mi.error(ResultCode.ERROR1200.getMessage(), ResultCode.ERROR1200.getStatus());
        }

        // ->确认订单,验证令牌
        // 获取登录后的信息
        MiUserEntity miUserEntity =
                AuthenticationInterceptor.threadLocal.get();
        String orderKey = Constant.USER_ORDER_TOKEN_PREFIX + miUserEntity.getUserId();

        //1、验证令牌【令牌的对比和删除必须保证原子性】
        //0令牌失败，1删除成功
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";

        //原子验证令牌和删除令牌
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(orderKey), orderToken);
        if (result == 0L) {
            // ->失败
            return Mi.error(ResultCode.ERROR1200.getMessage(), ResultCode.ERROR1200.getStatus());
        } else {
            // ->验证成功
            // 创建订单，订单项等信息
            // ->生成订单号
            String orderSn = "mi_" + IdWorker.getIdStr();
            OrderCreateTo order = createOrder(orderSubmitTo, orderSn);

            // TODO 验价暂时不做

            // 保存到数据库
            saveOrder(order);

            // 锁定库存,有异常回滚
            lockWare(order);

            // 清空购买的商品
            clearSelectCart(miUserEntity);

            // 返回订单号,支付价格 TODO 应该保存
            Map<String, Object> map = new HashMap<>();
            map.put("orderSn", orderSn);
            map.put("payPrice", order.getPayPrice());
            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), map);

        }
    }

    private void clearSelectCart(MiUserEntity miUserEntity) {
        String cartKey = Constant.CART_PREFIX + miUserEntity.getUserId();
        BoundHashOperations<String, Object, Object>
                cartOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = cartOps.values();
        if(values != null && values.size() > 0){
            ObjectMapper objectMapper = new ObjectMapper();
            for (Object value : values) {
                String str = (String) value;
                try {
                    CartItem cartItem = objectMapper.readValue(str, CartItem.class);
                    if(cartItem.getCheck()){
                        Integer goodsId = cartItem.getGoodsId();
                        cartOps.delete(goodsId.toString());
                    }
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public boolean updateOrderStatus(String outTradeNo, int code) {
        MiOrderEntity miOrderEntity = new MiOrderEntity();
        miOrderEntity.setStatus(code);
        boolean order_sn = this.update(miOrderEntity, new QueryWrapper<MiOrderEntity>().eq("order_sn", outTradeNo));
        return order_sn;
    }

    @Override
    public Mi myOrder(Integer pagenum, Integer pagesize) {
        MiUserEntity miUserEntity =
                AuthenticationInterceptor.threadLocal.get();
        if(pagenum != null && pagesize != null){
            if(pagenum <=0 || pagesize <= 0){
                return Mi.error(ResultCode.ERROR1204.getMessage(), ResultCode.ERROR1204.getStatus());
            }
            // 如果参数不为空,分页
            IPage<MiOrderEntity> page = new Page<>(pagenum, pagesize);
            this.page(page, new QueryWrapper<MiOrderEntity>().eq("user_id", miUserEntity.getUserId()));

            List<MiOrderEntity> records = page.getRecords();
            long total = page.getTotal();
            long current = page.getCurrent();
            long size = page.getSize();

            // 在根据order查询子项
            for (MiOrderEntity record : records) {
                String orderSn = record.getOrderSn();
                List<MiOrderItemEntity> orderItemEntities = miOrderItemService.list(new QueryWrapper<MiOrderItemEntity>().eq("order_sn", orderSn));
                record.setTime(DateUtils.formatDate(record.getCreateTime()));
                record.setChildren(orderItemEntities);
            }

            Map<String, Object> map = new HashMap<>();
            map.put("total", total);
            map.put("current", current);
            map.put("size", size);
            map.put("items", records);

            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), map);
        }
        List<MiOrderEntity> user_id =
                this.list(new QueryWrapper<MiOrderEntity>().eq("user_id", miUserEntity.getUserId()));
        return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), user_id);
    }

    @Transactional
    @Override
    public Mi cancelOrder(Integer orderId) {
        if(orderId == null){
            return Mi.error(ResultCode.ERROR1204.getMessage(), ResultCode.ERROR1204.getStatus());
        }
        MiOrderEntity byId = this.getById(orderId);
        if(byId != null){
            String orderSn = byId.getOrderSn();
            Integer id = byId.getId();
            // 删除订单项和订单
            boolean b = this.removeById(id);
            if(b){
                // 取消库存锁定
                List<MiOrderItemEntity> orderItemEntities =
                        miOrderItemService.list(new QueryWrapper<MiOrderItemEntity>().eq("order_sn", orderSn));
                if(orderItemEntities.size() > 0){
                    for (MiOrderItemEntity orderItemEntity : orderItemEntities) {
                        // 找到goods_id
                        Integer goodsId = orderItemEntity.getGoodsId();
                        Integer count = orderItemEntity.getCount();
                        MiWareEntity miWareEntity =
                                miWareService.getOne(new QueryWrapper<MiWareEntity>().eq("goods_id", goodsId));
                        if(miWareEntity != null){
                            Integer stockLocked = miWareEntity.getStockLocked();
                            int newLocked = stockLocked - count;
                            if(newLocked <= 0){
                                newLocked = 0;
                            }
                            miWareEntity.setStockLocked(newLocked);
                            // 更新
                            boolean b1 = miWareService.updateById(miWareEntity);
                            if(!b1){
                                throw new MiException(ResultCode.ERROR1205.getStatus(), ResultCode.ERROR1205.getMessage());
                            }
                        }
                    }
                } else {
                    throw new MiException(ResultCode.ERROR1205.getStatus(), ResultCode.ERROR1205.getMessage());
                }
                boolean remove = miOrderItemService.remove(new QueryWrapper<MiOrderItemEntity>().eq("order_sn", orderSn));
                if(!remove){
                    throw new MiException(ResultCode.ERROR1205.getStatus(), ResultCode.ERROR1205.getMessage());
                }
                return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), "取消订单成功！");
            }
            throw new MiException(ResultCode.ERROR1205.getStatus(), ResultCode.ERROR1205.getMessage());
        } else {
            throw new MiException(ResultCode.ERROR1205.getStatus(), ResultCode.ERROR1205.getMessage());
        }
    }

    private void lockWare(OrderCreateTo order) {
        List<MiOrderItemEntity> orderItems = order.getOrderItems();
        for (MiOrderItemEntity orderItem : orderItems) {
            Integer count = orderItem.getCount();
            Integer goodsId = orderItem.getGoodsId();

            QueryWrapper<MiWareEntity> queryWrapper =
                    new QueryWrapper<MiWareEntity>()
                            .eq("goods_id", goodsId);
            MiWareEntity one = miWareService.getOne(queryWrapper);
            if(one != null){
                // 库存足够
                if(one.getStock() - one.getStockLocked() > 0){
                    one.setUpdateTime(new Date());
                    one.setStockLocked(one.getStockLocked() + count);
                    miWareService.updateById(one);
                } else {
                    // 库存不够 回滚
                    throw new MiException(ResultCode.ERROR1300.getStatus(), ResultCode.ERROR1300.getMessage());
                }
            } else {
                // 库存不够 回滚
                throw new MiException(ResultCode.ERROR1300.getStatus(), ResultCode.ERROR1300.getMessage());
            }

        }
    }

    /**
     * 保存订单数据
     * @param order
     */
    private void saveOrder(OrderCreateTo order) {
        MiOrderEntity miOrderEntity = order.getOrder();
        boolean save = this.save(miOrderEntity);
        if(!save){
            throw new MiException(ResultCode.ERROR1206.getStatus(), ResultCode.ERROR1206.getMessage());
        }
        List<MiOrderItemEntity> orderItems = order.getOrderItems();
        boolean b = miOrderItemService.saveBatch(orderItems);
        if(!b){
            throw new MiException(ResultCode.ERROR1206.getStatus(), ResultCode.ERROR1206.getMessage());
        }

    }

    private OrderCreateTo createOrder(OrderSubmitTo orderSubmitTo, String orderSn) {
        OrderCreateTo orderCreateTo = new OrderCreateTo();

        // 订单
        MiOrderEntity miOrderEntity = buildOrderSn(orderSubmitTo, orderSn);
        orderCreateTo.setOrder(miOrderEntity);

        // 创建所有订单项
        List<MiOrderItemEntity> miOrderItemEntities = buildOrderItem(orderSn);
        orderCreateTo.setOrderItems(miOrderItemEntities);

        // 总价
        orderCreateTo.setPayPrice(orderSubmitTo.getPayPrice());

        // TODO 计算运费。验价，暂时不做

        return orderCreateTo;
    }

    private List<MiOrderItemEntity> buildOrderItem(String orderSn) {
        MiUserEntity miUserEntity =
                AuthenticationInterceptor.threadLocal.get();
        String cartKey = Constant.CART_PREFIX + miUserEntity.getUserId();
        BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = cartOps.values();
        List<MiOrderItemEntity> miOrderItemEntities = new ArrayList<>();
        if(values != null && values.size() > 0){
            for (Object value : values) {
                String str = (String) value;
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    CartItem cartItem = objectMapper.readValue(str, CartItem.class);
                    if (cartItem.getCheck()) {
                        MiOrderItemEntity miOrderItemEntity = new MiOrderItemEntity();
                        miOrderItemEntity.setOrderSn(orderSn);
                        miOrderItemEntity.setGoodsId(cartItem.getGoodsId());
                        miOrderItemEntity.setTitle(cartItem.getTitle());
                        miOrderItemEntity.setImage(cartItem.getImage());
                        miOrderItemEntity.setPrice(cartItem.getPrice());
                        miOrderItemEntity.setCount(cartItem.getCount());
//                        miOrderItemEntity.setAttrs(StringUtils.collectionToDelimitedString(cartItem.getAttr(), ";"));
                        miOrderItemEntity.setAttrs(cartItem.getAttr());
                        miOrderItemEntity.setTotalPrice(cartItem.getTotalPrice());
                        miOrderItemEntity.setCreateTime(new Date());
                        miOrderItemEntity.setUpdateTime(new Date());
                        miOrderItemEntities.add(miOrderItemEntity);
                    }
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
        }
        return miOrderItemEntities;
    }

    private MiOrderEntity buildOrderSn(OrderSubmitTo orderSubmitTo, String orderSn) {
        MiUserEntity miUserEntity =
                AuthenticationInterceptor.threadLocal.get();
        MiOrderEntity miOrderEntity = new MiOrderEntity();
        miOrderEntity.setUserId(miUserEntity.getUserId());
        miOrderEntity.setOrderSn(orderSn);
        // 0未付款
        miOrderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        // 地址
        miOrderEntity.setReceiverId(Integer.parseInt(orderSubmitTo.getAddrId()));
        miOrderEntity.setTotalAmount(orderSubmitTo.getPayPrice());
        miOrderEntity.setPayType(Integer.parseInt(orderSubmitTo.getPayType()));
        miOrderEntity.setPayAmount(orderSubmitTo.getPayPrice());
        miOrderEntity.setCreateTime(new Date());
        miOrderEntity.setModifyTime(new Date());
        miOrderEntity.setNote(orderSubmitTo.getNote());

        return miOrderEntity;
    }
}
